/*
*
* nicerun - Utility to run a process as a certain user with a certain priority
*
* Author:      Bas 'soczol' Verhoeven 
* Contact:     basverhoeven@users.sourceforge.net
*
* Copyright (C) 2007 Bas 'soczol' Verhoeven
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
* 
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <pwd.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int uid = 0, gid = 0;
    int prio = 0;

    struct passwd *pwentry;

    if (argc != 4 && (argc < 2 || strcasecmp(argv[1], "--help") != 0))  {
        printf("%s: not enough parameters\n", argv[0]);
        printf("Try `%s --help' for more information.\n", argv[0]);
        return 0;
    } else if(argc != 4) {
        printf("Usage: %s <user> <priority> <command>\n", argv[0]);
        printf("Run a command with an adjusted scheduling priority as a certain user.\n");
        printf("Priority range goes from -20 (highest priority) to 19 (lowest).\n");
        printf("\n");
        printf("Report bugs to: <basverhoeven@users.sourceforge.net>\n");
        return 0;
    }

    // We need to be root to set priorities
    if (getuid() != 0) {
        printf("Error: Need root privileges to be able to change priorities and change userid.\n");
        return 0;
    }

    // Attempt to find the uid
    if ((pwentry = getpwnam(argv[1])) != NULL) {
        uid = pwentry->pw_uid;
        gid = pwentry->pw_gid;
    } else {
        printf("Error: User '%s' not found\n", argv[1]);
        return 0;
    }
    
    if (strcasecmp(argv[2], "0") != 0 && ((prio = atoi(argv[2])) == 0 || (prio > 19 || prio < -20))) {
        printf("Error: Invalid priority specified.\n");
        return 0;
    }
    
    // Set the priority
    if (setpriority(PRIO_PGRP, getpid(), prio) < 0) {
        perror("Error: Could not set priority");
        return 0;
    }
    
    // Change to the specified group
    if (setgid(gid) < 0) {
        perror("Error: Could not change group");
        return 0;
    }

    // Change to the specified user
    if (setuid(uid) < 0) {
        perror("Error: Could not change user");
        return 0;
    }

    // Run the process
    return system(argv[3]);
}
